package com.xnyzc.lhy.statistics.service.impl.search;

import com.xnyzc.lhy.common.constant.RedisPrefixConstant;
import com.xnyzc.lhy.common.entity.Rv;
import com.xnyzc.lhy.common.util.CheckUtil;
import com.xnyzc.lhy.common.util.DateUtil;
import com.xnyzc.lhy.common.util.IDUtil;
import com.xnyzc.lhy.statistics.component.es.JestService;
import com.xnyzc.lhy.statistics.entity.param.capacity.CapacityParam;
import com.xnyzc.lhy.statistics.entity.statistics.ActiveDriver;
import com.xnyzc.lhy.statistics.entity.statistics.DriveOut;
import com.xnyzc.lhy.statistics.mapper.statistics.CollectCapacityStatisticalMapper;
import com.xnyzc.lhy.statistics.service.search.CapacitySearchService;
import io.searchbox.client.JestResult;
import io.searchbox.core.Bulk;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import io.searchbox.core.search.aggregation.TermsAggregation;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 订单搜索服务类
 *
 * @author cuixiaojian
 */
@Slf4j
@Service
public class CapacitySearchServiceImpl implements CapacitySearchService {

    @Autowired
    private JestService restService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CollectCapacityStatisticalMapper collectCapacityStatisticalMapper;

    /**
     * 保存司机出车统计
     * @return
     */
    @Override
    public Rv saveDriveOutCount() {

        List<Map<String, Object>> mapList =  collectCapacityStatisticalMapper.searchDriveOutCount();

        Date now = new Date();
        JestResult jestResult=null;

        List<DriveOut> driveOuts = new ArrayList<>();

        if (CheckUtil.collectionIsNotEmpty(mapList)) {

            for (Map<String, Object> map : mapList) {

                DriveOut driveOut = new DriveOut();

                driveOut.setCount(Integer.parseInt(map.get("count").toString()));
                driveOut.setAdcode(map.get("adcode").toString());

                driveOut.setDateTime(now);
                driveOut.setDate(DateUtil.convertToStringCustom(now, "yyyy-MM-dd"));
                driveOut.setTime(DateUtil.convertToStringCustom(now, "HH:mm"));

                driveOuts.add(driveOut);

            }

        }

        // 建造容器
        Bulk.Builder bulk = new Bulk.Builder();

        for (DriveOut driveOut : driveOuts) {
            // 构造索引
            Index index = new Index.Builder(driveOut).index(DriveOut.INDEX_NAME).type(DriveOut.TYPE).id(String.valueOf(IDUtil.nextId())).build();
            bulk.addAction(index);

            log.info("index值:{}", index.toString());

        }

        jestResult = restService.jestExecute(bulk.build());

        return Rv.wrap(jestResult.isSucceeded());

    }

    /**
     * 保存日活司机数量
     */
    @Override
    public Rv saveActiveDriver() {

        Date now = new Date();

        Set<Map<String, String>> set = redisTemplate.opsForSet().members(RedisPrefixConstant.DRIVER_ACTIVE);

        List<ActiveDriver> activeDrivers = new ArrayList<>();

        for (Map<String, String> map : set) {
            if (CheckUtil.collectionIsEmpty(activeDrivers)) {
                ActiveDriver activeDriver = new ActiveDriver();
                activeDriver.setAdcode(map.get("adcode"));
                activeDriver.setCount(1);
                activeDriver.setDate(DateUtil.convertToStringCustom(now, "yyyy-MM-dd"));
                activeDrivers.add(activeDriver);
            } else {
                for (ActiveDriver activeDriver : activeDrivers) {
                    if (map.get("adcode").equals(activeDriver.getAdcode())) {
                        activeDriver.setCount(activeDriver.getCount() + 1);
                    } else {
                        ActiveDriver activeDriverItem = new ActiveDriver();
                        activeDriverItem.setAdcode(map.get("adcode"));
                        activeDriverItem.setCount(1);
                        activeDriverItem.setDate(DateUtil.convertToStringCustom(now, "yyyy-MM-dd"));
                        activeDrivers.add(activeDriverItem);
                        break;
                    }
                }
            }
        }

        JestResult jestResult = null;

        // 建造容器
        Bulk.Builder bulk = new Bulk.Builder();

        for (ActiveDriver activeDriver : activeDrivers) {
            Index index = new Index.Builder(activeDriver).index(ActiveDriver.INDEX_NAME).type(ActiveDriver.TYPE).id(String.valueOf(IDUtil.nextId())).build();
            bulk.addAction(index);
        }

        jestResult = restService.jestExecute(bulk.build());

        // 保存完成后，清除redis缓存，继续开始第二天
        redisTemplate.delete(RedisPrefixConstant.DRIVER_ACTIVE);

        return Rv.wrap(jestResult.isSucceeded());
    }

    /**
     * 查询日活司机数
     * @return
     */
    @Override
    public List<Map<String, Object>> getActiveDriver(CapacityParam capacityParam) {

        SearchResult searchResult = null;

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        queryBuilder.must(QueryBuilders.rangeQuery(ActiveDriver.DATE).gt(capacityParam.getTimeList().get(0)).lt(capacityParam.getTimeList().get(1)));

        if (CheckUtil.objIsNotEmpty(capacityParam.getCityId())) {
            // 匹配ad_code
            queryBuilder.must(QueryBuilders.matchQuery(ActiveDriver.ADCODE,capacityParam.getCityId()));
        } else {
            // 聚合求最大值
            AggregationBuilder aggregationBuilder =
                    AggregationBuilders.terms(ActiveDriver.COUNT).field(ActiveDriver.DATE).size(Integer.MAX_VALUE)
                            .subAggregation(AggregationBuilders.max(ActiveDriver.COUNT).field(ActiveDriver.COUNT));

            searchSourceBuilder.aggregation(aggregationBuilder);
        }

        searchSourceBuilder.query(queryBuilder);

        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(ActiveDriver.INDEX_NAME).build();

        log.info("执行查询语句：{}", searchSourceBuilder.toString());

        searchResult = restService.searchExecute(search);

        List<TermsAggregation.Entry> entries = searchResult.getAggregations().getTermsAggregation(ActiveDriver.COUNT).getBuckets();

        List<Map<String, Object>> resultMap = new ArrayList<>();

        for (TermsAggregation.Entry entry : entries) {

            Map<String, Object> result = new HashMap<>(2);

            String date = entry.getKeyAsString();
            // 将时间类型 [ 2019-12-15T00:00:00.000Z ] 截取为 [ 2019-12-15 ] 格式
            date = date.substring(0, date.indexOf('T'));
            date = date.substring(0, 4) + "|" + date.substring(5, date.length());

            result.put("time", date);
            result.put("account", entry.getMaxAggregation(ActiveDriver.COUNT).getMax().intValue());
            resultMap.add(result);

        }

        return resultMap;
    }

    /**
     * 获取出车司机折线图
     * @return Rv
     */
    @Override
    public List<Map<String, Object>> getDriveOutLineChart(CapacityParam capacityParam) {

        SearchResult searchResult = null;
        JestResult jestResult = null;

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        if (CheckUtil.objIsNotEmpty(capacityParam.getCityId())) {
            queryBuilder.must(QueryBuilders.matchQuery(DriveOut.ADCODE,capacityParam.getCityId()));
        }

        // 时间范围检索
        queryBuilder.must(QueryBuilders.rangeQuery(DriveOut.DATE).gt(capacityParam.getTimeList().get(0)).lt(capacityParam.getTimeList().get(1)));

        if (!(capacityParam.getChartType() == 3)) {

            // 以天为颗粒度查询
            AggregationBuilder aggregationBuilder =
                    AggregationBuilders.terms(DriveOut.AGG_DATE).field(DriveOut.DATE).size(Integer.MAX_VALUE)
                            .subAggregation(AggregationBuilders.max(DriveOut.AGG_COUNT).field(DriveOut.COUNT));

            searchSourceBuilder.aggregation(aggregationBuilder);

        }

        searchSourceBuilder.query(queryBuilder);

        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(DriveOut.INDEX_NAME).addType(DriveOut.TYPE).build();

        log.info("执行查询语句：{}", searchSourceBuilder.toString());

        List<Map<String, Object>> resultMap = new ArrayList<>();

        if (!(capacityParam.getChartType() == 3)) {

            searchResult = restService.searchExecute(search);

            List<TermsAggregation.Entry> entries = searchResult.getAggregations().getTermsAggregation(DriveOut.AGG_DATE).getBuckets();

            for (TermsAggregation.Entry entry : entries) {

                Map<String, Object> result = new HashMap<>(2);

                String date = entry.getKeyAsString();
                // 将时间类型 [ 2019-12-15T00:00:00.000Z ] 截取为 [ 2019-12-15 ] 格式
                date = date.substring(0, date.indexOf('T'));
                date = date.substring(0, 4) + "|" + date.substring(5, date.length());

                log.info("时间为:", date);
                log.info("总数为:", entry.getMaxAggregation(DriveOut.AGG_COUNT).getMax().intValue());

                result.put("time", date);
                result.put("account", entry.getMaxAggregation(DriveOut.AGG_COUNT).getMax().intValue());
                resultMap.add(result);

            }

            return resultMap;

        }

        jestResult = restService.jestExecute(search);

        List<DriveOut> driveOuts = jestResult.getSourceAsObjectList(DriveOut.class);

        for (DriveOut driveOut : driveOuts) {

            Map<String, Object> result = new HashMap<>(2);

            String time = driveOut.getTime().replaceAll("-", ":");

            result.put("time", time);
            result.put("account", driveOut.getCount());

            resultMap.add(result);

        }

        return resultMap;

    }

}
